<html>
<head>
	<title>数独提示小工具</title>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<style type="text/css">
		.gray { background-color:#006600
		}
		.solid {
			border:solid black;
		}
		.dot {
			border:1px red;
		}
		td td{
			width:30px;height:30px;align:center;background-color:#C0C0C0;font-weight:bold;font-size:24;
		}
	</style>
	<script type="text/javascript">
		var $ = function(id){
			return document.getElementById(id);
		}
		var f = function(){}
		var data = new Array();
		var dataBack = new Array();
		function loop81(before,middle,after){
			for(var i=0;i<9;i++){
				before(i);
				for(var j=0;j<9;j++){
					middle(i,j);
				}
				after(i);
			}
		}
		function init(){
			loop81(function(i){data.push(new Array());dataBack.push(new Array());},
					function(i,j){data[i].push(0);dataBack[i].push(0);},f);
			data[0][1] = 6;
			data[0][3] = 9;
			data[0][7] = 3;
			data[1][7] = 1;
			data[1][4] = 5;
			data[1][2] = 9;
			data[2][2] = 2;
			data[3][2] = 6;
			data[3][6] = 5;
			data[4][0] = 5;
			data[4][5] = 2;
			data[4][8] = 8;
			data[5][2] = 1;
			data[5][5] = 3;
			data[5][6] = 9;
			data[6][6] = 8;
			data[7][1] = 7;
			data[7][4] = 3;
			data[7][6] = 4;
			data[0][1] = 6;
			data[8][1] = 2;
			data[8][5] = 1;
			data[8][7] = 7;
			//********************************/
			
			function createBlock(row,col){
				function createBlockTr(row,col){
					var sb = "<tr>";
					for(var i=0;i<3;i++){
						sb += "<td border='1' id='"+"td-"+row+"-"+(col+i)+"' onclick='clickTd(this);' onmouseover='mouseOver(this);' onmouseout='mouseout(this);'>"+(data[row][col+i]==0?"":data[row][col+i])+"</td>";
					}
					return sb;
				}
				var sb = "<table>";
				for(var i=0;i<3;i++){
					sb += createBlockTr(row+i,col);
				}
				sb += "</table>";
				return sb;
			}
			// 先生成每个小方块，再组合成大table
			var sb = "<table cellpadding='0' cellspacing='0'>";
			for(var j=0;j<3;j++){
			sb += "<tr>";
			for(var i=0;i<3;i++){
				sb += "<td class='solid'>"+createBlock(j*3,3*i)+"</td>";
			}
			sb += "</tr>";
			}
			sb += "</table>";
			container.innerHTML = sb;
		}
		// mouse 滑过数字，只有当方块内有数字时 才会显示提示
		function mouseOver(obj){
			if(obj.innerHTML != ""){
				var value = Number(obj.innerHTML)
				loop81(f,function(i,j){if(data[i][j] == value){grayCell($("td-"+i+"-"+j));}},f);
			}
		}
		function mouseout(obj){
			if(obj.innerHTML != ""){
				var value = Number(obj.innerHTML)
				loop81(f,function(i,j){if(data[i][j] == value){whiteCell($("td-"+i+"-"+j));}},f);
			}
		}
		function clickTd(obj){
			var input = prompt("输入数字(0-9)","");
			
			if(input != null && /^[0-9]$/.test(input)){
				var id = obj.id;
				var row = Number(id.substring(3,4));
				var col = Number(id.substring(5,6));
				data[row][col] = Number(input);
				obj.innerHTML = (input=="0"?"":input);
			}
			
		}
		function grayCell(obj){
			grayOrWhiteAllCell(obj,"gray","red");
		}
		function whiteCell(obj){
			grayOrWhiteAllCell(obj,"","black");
		}
		function grayOrWhiteAllCell(obj,name,color){
			var id = obj.id;
			var row = Number(id.substring(3,4));
			var col = Number(id.substring(5,6));
			obj.className = name;
			obj.style.color = color;
			var orow = row - row %3;
			var ocol = col - col%3;
			for(var i=0;i<9;i++){
				$("td-"+row+"-"+i).className = name;
				$("td-"+i+"-"+col).className = name;
				$("td-"+(orow+(i-i%3)/3)+"-"+(ocol+i%3)).className = name;
			}
		}
		
		function autoCrack(){
			crackSimpleNum();
			while(! isSuccess() && testCrack()){
				crackSimpleNum();
			}
			alert("破解完成");
		}
		function testCrack(){
			save();
			for(var num = 1;num<10;num++){
				var indexs = getTestCell(num);
				if(indexs.length > 0){
					for(var i=0;i<indexs.length;i++){
						if(testTheCell(indexs[i],num)){
							return true;
						}
					}
				}
			}
			return false;
		}
		function getTestCell(num){
			grayAllCell(num);
			var result = new Array();
			for(var row=0;row<9;row++){
				var temp = new Array();				
				for(var col=0;col<9;col++){
					if(getTd(row,col).innerHTML == "" && getTd(row,col).className == ""){
						temp.push(row);
						temp.push(col);
					}
				}
				if(temp.length == 4){
					result.push(temp);
				}
			}
			whiteAllCell(num);
			return result;
		}
		function testTheCell(index,num){
			var processit = function(row,col){
				var td = getTd(row,col);
				td.innerHTML = ""+num;
				data[row][col] = num;
				crackSimpleNum();
			}
			var row = index[0];
			var col = index[1];
			processit(row,col);
			if(isSuccess()){
				return true;
			}else{
				backup();
				if(! isVerify()){
					getTd(index[2],index[3]).innerHTML = ""+num;
					data[index[2]][index[3]] = num;
					return true;
				}else{
					row = index[2];
					col = index[3];
					processit(row,col);
					if(isSuccess()){
						return true;
					}else{
						backup();
						if(isVerify()){
							return false;
						}else{
							getTd(index[0],index[1]).innerHTML = ""+num;
							data[index[0]][index[1]] = num;
							return true;
						}
					}
				}
			}
		}
		
		function isSuccess(){
			for(var i=0;i<9;i++){
				for(var j=0;j<9;j++){
					if(data[i][j] == 0){
						return false;
					}
				}
			}
			return true;
		}
		function isVerify(){
			for(var i=1;i<10;i++){
				if(isFullCover(i) && !isFullNum(i)){
					return false;
				}
			}
			return true;
		}
		function isFullCover(num){
			grayAllCell(num);
			for(var i=0;i<9;i++){
				for(var j=0;j<9;j++){
					var td = getTd(i,j);
					if(td.className == "" && td.innerHTML == ""){
						whiteAllCell(num);
						return false;
					}
				}
			}
			whiteAllCell(num);
			return true;
		}
		function isFullNum(num){
			var index = 0;
			for(var i=0;i<9;i++){
				for(var j=0;j<9;j++){
					if(data[i][j] == num){
						index++;
					}
				}
			}
			if(index == 9){
				return true;
			}else{
				return false;
			}
		}
		function crackSimpleNum(){
			var result = true;
			while(result){
				result = loopCrack() || loopOneCrack() ;
			}
		}
		// 唯一候选数字法 
		function loopOneCrack(){
			var result = new Array();	
			for(var row = 0;row<9;row++){
				for(var col =0;col<9;col++){
					if(data[row][col] == 0){
						var r = new Array();
						r.push(row);r.push(col);
						result.push(r);
					}
				}
			}
			if(result.length >0){
				for(var j=0;j<result.length;j++){
					var temp = new Array();
					for(var i=0;i<9;i++){
						temp.push(0);
					}
					var row = result[j][0];
					var col = result[j][1];
					for(var i=0;i<9;i++){
						var td = getTd(row,i);
						if(td.innerHTML != ""){
							temp[Number(td.innerHTML)-1] = 1;
						}
						td = getTd(i,col);
						if(td.innerHTML != ""){
							temp[Number(td.innerHTML)-1] = 1;
						}
						var orow = row - row%3;
						var ocol = col - col%3;
						td = getTd(orow + (i - i%3)/3,ocol + i%3);
						if(td.innerHTML != ""){
							temp[Number(td.innerHTML)-1] = 1;
						}
					}
					var r = 10;
					for(var i =0;i<9;i++){
						if(temp[i] == 0 ){
							if(r != 10){
								r = 10;
								break;
							}else{
								r = i;
							}
						}
					}
					if(r != 10){
						data[row][col] = r+1;
						getTd(row,col).innerHTML = ""+(r+1);
						return true;
					}
				}
			}
			return false;	
		}
		
		// 这个算是隐性 唯一候选数字法 
		function loopCrack(){
			
			for(var i=1;i<10;i++){
				if(scanNum(i)){
					return true;
				}
			}
			return false;
		}
		function scanNum(num){
			grayAllCell(num);
			var result = crackTheCell(num);
			whiteAllCell(num);
			return result;
		}
		function crackTheCell(num){
			var result = scanTheRowCell(num);
			var result = result || scanTheColCell(num);
			var result = result || scanTheBlockCell(num);
			return result;
		}
		function scanTheRowCell(num){
			var result = false;
			for(var row=0;row<9;row++){
				var emptyCell = 10;
				for(var col=0;col<9;col++){
					var td = getTd(row,col);
					if(td.className == "" && td.innerHTML == ""){
						if(emptyCell == 10){
							emptyCell = col;
						}else{
							emptyCell = 10;
							break;
						}
					}
				}
				if(emptyCell != 10){
					getTd(row,emptyCell).innerHTML = ""+num;
					data[row][emptyCell] = num;
					return  true;
					
				}
			}
			return result;
		}
		
		function scanTheColCell(num){
			var result = false;
			for(var col=0;col<9;col++){
				var cell = 10;
				for(var row=0;row<9;row++){
					var td = getTd(row,col);
					if(td.innerHTML == "" && td.className == ""){
						if(cell == 10){
							cell = row;
						}else{
							cell =10;
							break;
						}
					}
				}
				if(cell != 10){
					getTd(cell,col).innerHTML = ""+num;
					data[cell][col] = num;
					return  true;
				}
			}
			return result;
		}
		
		function scanTheBlockCell(num){
			var result = false;
			for(var row=0;row<9;row++){
				var cell = 10;
				for(var col=0;col<9;col++){
					var td = getTd((row-row%3)+(col-col%3)/3,row%3*3+col%3);
					if(td.innerHTML == "" && td.className == ""){
						if(cell == 10){
							cell = col;
						}else{
							cell =10;
							break;
						}
					}
				}
				if(cell != 10){
					getTd((row-row%3)+(cell-cell%3)/3,row%3*3+cell%3).innerHTML = ""+num;
					data[(row-row%3)+(cell-cell%3)/3][row%3*3+cell%3] = num;
					return  true;
				}
			}
			return result;
		}
		
		function grayAllCell(num){
			for(var i=0;i<9;i++){
				for(var j=0;j<9;j++){
					if(data[i][j] == num){
						grayCell(getTd(i,j));
					}
				}
			}
		}
		function whiteAllCell(num){
			for(var i=0;i<9;i++){
				for(var j=0;j<9;j++){
					if(data[i][j] == num){
						whiteCell(getTd(i,j));
					}
				}
			}
		}
		function getTd(row,col){
			return document.getElementById("td-"+row+"-"+col);
		}
		function println(){
			var content = "";
			for(var i=0;i<9;i++){
				for(var j=0;j<9;j++){
					content += "" + data[i][j] + ",";
				}
				content += "\r\n";
			}
			alert(content)
		}
		function autoTip(){
			loopCrack();
		}
		function save(){
			loop81(f,function(i,j){dataBack[i][j] = data[i][j];},f);
		}
		function backup(){
			loop81(f,function(i,j){data[i][j] = dataBack[i][j];},f);
			init();
		}
	</script>
</head>

<body onload="init();">
	<div id="container" style="align:center;top:50px;" onmouseover="">
		<td ></td>
	</div>
	<button onclick="autoCrack();">自动破解</button>
	<button onclick="autoTip();">提示一个数字</button>
	<button onclick="save();">保存</button>
	<button onclick="backup();">还原</button>
</body>
</html>